package com.mxpio.erp.inventory.service.impl;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.mxpio.erp.common.enums.NoticeStatusEnums;
import com.mxpio.erp.common.enums.OrderEnums;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.inventory.entity.InvFlow;
import com.mxpio.erp.common.inventory.entity.ToNotice;
import com.mxpio.erp.common.inventory.entity.ToNoticeLine;
import com.mxpio.erp.common.inventory.entity.TransferOrder;
import com.mxpio.erp.common.inventory.entity.TransferOrderLine;
import com.mxpio.erp.common.inventory.entity.WarehouseOrder;
import com.mxpio.erp.common.inventory.entity.WarehouseOrderLine;
import com.mxpio.erp.common.inventory.service.TransferOrderLineService;
import com.mxpio.erp.common.jpa.model.NoticeLine;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.system.service.impl.BaseServiceImpl;

@Service
public class TransferOrderLineServiceImpl extends BaseServiceImpl<TransferOrderLine> implements TransferOrderLineService {

	@Override
	@Transactional(readOnly = true)
	public void handleBillQuantity(String bizNo,List<TransferOrderLine> transferOrderLines) {
		Map<String, BigDecimal> quantity = new HashMap<>();
		TransferOrder order = JpaUtil.linq(TransferOrder.class).idEqual(bizNo).findOne();
		
		//获取实际执行数量
		List<InvFlow> flows = JpaUtil.linq(InvFlow.class).equal("originBizNo", bizNo).list();
		for(InvFlow flow : flows){
			// 根据仓库判断出/入
			if(order.getOriginWhCode().equals(flow.getWhCode())){
				BigDecimal actualOutQuantity = quantity.get("actual:"+flow.getOriginBizNo()+flow.getOriginBizLineNo()+":out");
				if(actualOutQuantity == null){
					actualOutQuantity = BigDecimal.ZERO;
				}
				// 出库仓库 若AccessType为OUT 则为出库，in为退货
				if(OrderEnums.AccessType.IN.getCode().equals(flow.getAccessType())){
					actualOutQuantity = actualOutQuantity.subtract(flow.getQuantity());
				}else{
					actualOutQuantity = actualOutQuantity.add(flow.getQuantity());
				}
				quantity.put("actual:"+flow.getOriginBizNo()+flow.getOriginBizLineNo()+":out", actualOutQuantity);
			}else if(order.getWhCode().equals(flow.getWhCode())){
				BigDecimal actualInQuantity = quantity.get("actual:"+flow.getOriginBizNo()+flow.getOriginBizLineNo()+":in");
				if(actualInQuantity == null){
					actualInQuantity = BigDecimal.ZERO;
				}
				// 入库仓库 若AccessType为IN 则为入库，OUT为退货
				if(OrderEnums.AccessType.IN.getCode().equals(flow.getAccessType())){
					actualInQuantity = actualInQuantity.add(flow.getQuantity());
				}else{
					actualInQuantity = actualInQuantity.subtract(flow.getQuantity());
				}
				quantity.put("actual:"+flow.getOriginBizNo()+flow.getOriginBizLineNo()+":in", actualInQuantity);
			}
		}
		//获取计划执行数量
		//1.计算未完成通知单数量
		List<ToNotice> notices = JpaUtil.linq(ToNotice.class).collect("noticeNo", ToNoticeLine.class, "noticeNo")
				.equal("noticeStatus", NoticeStatusEnums.NoticeStatus.CREATE.getStatusCode()).equal("bizOrderNo", bizNo)
				.list();
		
		for(ToNotice notice : notices){
			// 根据仓库判断出/入
			if(order.getOriginWhCode().equals(notice.getWhCode())){
				for(NoticeLine line : notice.getNoticeLines()){
					// 出库仓库 若AccessType为OUT 则为出库，in为退货
					if(OrderEnums.AccessType.OUT.getCode().equals(notice.getAccessType())){
						BigDecimal planOutQuantity = quantity.get("plan:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":out");
						if(planOutQuantity == null){
							planOutQuantity = BigDecimal.ZERO;
						}
						planOutQuantity = planOutQuantity.add(line.getQuantity());
						quantity.put("plan:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":out", planOutQuantity);
					}else{
						// 计划退货
						BigDecimal planRejectInQuantity = quantity.get("planReject:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":in");
						if(planRejectInQuantity == null){
							planRejectInQuantity = BigDecimal.ZERO;
						}
						planRejectInQuantity = planRejectInQuantity.add(line.getQuantity());
						quantity.put("planReject:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":in", planRejectInQuantity);
					}
				}
			}else if(order.getWhCode().equals(notice.getWhCode())){
				for(NoticeLine line : notice.getNoticeLines()){
					// 入库仓库 若AccessType为IN 则为入库，OUT为退货
					if(OrderEnums.AccessType.IN.getCode().equals(notice.getAccessType())){
						BigDecimal planInQuantity = quantity.get("plan:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":in");
						if(planInQuantity == null){
							planInQuantity = BigDecimal.ZERO;
						}
						planInQuantity = planInQuantity.add(line.getQuantity());
						quantity.put("plan:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":in", planInQuantity);
					}else{
						BigDecimal planRejectOutQuantity = quantity.get("planReject:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":out");
						if(planRejectOutQuantity == null){
							planRejectOutQuantity = BigDecimal.ZERO;
						}
						planRejectOutQuantity = planRejectOutQuantity.add(line.getQuantity());
						quantity.put("planReject:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":out", planRejectOutQuantity);
					}
				}
			}
		}
		
		//2.计算为完成仓单数量
		List<WarehouseOrder> wos = JpaUtil.linq(WarehouseOrder.class)
				.equal("closeStatus", OrderStatusEnums.CloseStatus.OPEN.getStatusCode())
				.notEqual("orderStatus", OrderStatusEnums.OrderStatus.FINISHED.getStatusCode())
				.equal("originBizNo", bizNo).list();
		
		//2.1 
		Set<String> outWoNos = new HashSet<>();
		Set<String> inRejectWoNos = new HashSet<>();
		Set<String> inWoNos = new HashSet<>();
		Set<String> outRejectWoNos = new HashSet<>();
		Set<String> woNos = new HashSet<>();
		for(WarehouseOrder wo : wos){
			if(order.getOriginWhCode().equals(wo.getWhCode())&&OrderEnums.AccessType.OUT.getCode().equals(wo.getAccessType())){
				outWoNos.add(wo.getBizNo());
			}else if(order.getOriginWhCode().equals(wo.getWhCode())&&OrderEnums.AccessType.IN.getCode().equals(wo.getAccessType())){
				inRejectWoNos.add(wo.getBizNo());
			}else if(order.getWhCode().equals(wo.getWhCode())&&OrderEnums.AccessType.IN.getCode().equals(wo.getAccessType())){
				inWoNos.add(wo.getBizNo());
			}else if(order.getWhCode().equals(wo.getWhCode())&&OrderEnums.AccessType.OUT.getCode().equals(wo.getAccessType())){
				outRejectWoNos.add(wo.getBizNo());
			}
			woNos.add(wo.getBizNo());
		}
		//2.2分别计算各类型未执行仓单数量
		List<InvFlow> invFlows = JpaUtil.linq(InvFlow.class).in("woBizNo", woNos).list();
		Map<String, BigDecimal> flowMap = new HashMap<>();
		// 汇总按照入库为正
		invFlows.forEach(flow -> {
			BigDecimal sumQuantity = flowMap.get(flow.getWoBizNo()+flow.getWoBizLineNo());
			if(sumQuantity == null){
				sumQuantity = BigDecimal.ZERO;
			}
			if(OrderEnums.AccessType.IN.getCode().equals(flow.getAccessType())){
				sumQuantity = sumQuantity.add(flow.getQuantity());
			}else{
				sumQuantity = sumQuantity.subtract(flow.getQuantity());
			}
			flowMap.put(flow.getWoBizNo()+flow.getWoBizLineNo(), sumQuantity);
		});
		// 根据仓库判断出/入
		List<WarehouseOrderLine> outLines = JpaUtil.linq(WarehouseOrderLine.class)
				.in("bizNo", outWoNos)
				.equal("closeStatus", OrderStatusEnums.CloseStatus.OPEN.getStatusCode()).list();
		for(WarehouseOrderLine line : outLines){
			BigDecimal planOutQuantity = quantity.get("plan:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":out");
			BigDecimal sumQuantity = flowMap.get(line.getBizNo()+line.getLineNo());
			if(planOutQuantity == null){
				planOutQuantity = BigDecimal.ZERO;
			}
			if(sumQuantity == null){
				sumQuantity = BigDecimal.ZERO;
			}
			planOutQuantity = planOutQuantity.add(line.getQuantity().add(sumQuantity));
			quantity.put("plan:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":out", planOutQuantity);
		}
		List<WarehouseOrderLine> inRejectLines = JpaUtil.linq(WarehouseOrderLine.class)
				.in("bizNo", inRejectWoNos)
				.equal("closeStatus", OrderStatusEnums.CloseStatus.OPEN.getStatusCode()).list();
		for(WarehouseOrderLine line : inRejectLines){
			// 计划退货
			BigDecimal planRejectInQuantity = quantity.get("planReject:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":in");
			BigDecimal sumQuantity = flowMap.get(line.getBizNo()+line.getLineNo());
			if(planRejectInQuantity == null){
				planRejectInQuantity = BigDecimal.ZERO;
			}
			if(sumQuantity == null){
				sumQuantity = BigDecimal.ZERO;
			}
			planRejectInQuantity = planRejectInQuantity.add(line.getQuantity().subtract(sumQuantity));
			quantity.put("planReject:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":in", planRejectInQuantity);
		}
		List<WarehouseOrderLine> inLines = JpaUtil.linq(WarehouseOrderLine.class)
				.in("bizNo", inWoNos)
				.equal("closeStatus", OrderStatusEnums.CloseStatus.OPEN.getStatusCode()).list();
		for(WarehouseOrderLine line : inLines){
			// 计划入库
			BigDecimal planInQuantity = quantity.get("plan:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":in");
			BigDecimal sumQuantity = flowMap.get(line.getBizNo()+line.getLineNo());
			if(planInQuantity == null){
				planInQuantity = BigDecimal.ZERO;
			}
			if(sumQuantity == null){
				sumQuantity = BigDecimal.ZERO;
			}
			planInQuantity = planInQuantity.add(line.getQuantity().subtract(sumQuantity));
			quantity.put("plan:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":in", planInQuantity);
		}
		List<WarehouseOrderLine> outRejectLines = JpaUtil.linq(WarehouseOrderLine.class)
				.in("bizNo", outRejectWoNos)
				.equal("closeStatus", OrderStatusEnums.CloseStatus.OPEN.getStatusCode()).list();
		for(WarehouseOrderLine line : outRejectLines){
			BigDecimal planRejectOutQuantity = quantity.get("planReject:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":out");
			BigDecimal sumQuantity = flowMap.get(line.getBizNo()+line.getLineNo());
			if(planRejectOutQuantity == null){
				planRejectOutQuantity = BigDecimal.ZERO;
			}
			if(sumQuantity == null){
				sumQuantity = BigDecimal.ZERO;
			}
			planRejectOutQuantity = planRejectOutQuantity.add(line.getQuantity().add(sumQuantity));
			quantity.put("planReject:"+line.getOriginBizNo()+line.getOriginBizLineNo()+":out", planRejectOutQuantity);
		}
		
		//写入数量
		transferOrderLines.forEach(transferOrderLine -> {
			transferOrderLine.setActualInQuantity(quantity.get("actual:"+transferOrderLine.getBizNo()+transferOrderLine.getLineNo()+":in"));
			transferOrderLine.setActualOutQuantity(quantity.get("actual:"+transferOrderLine.getBizNo()+transferOrderLine.getLineNo()+":out"));
			transferOrderLine.setPlanInQuantity(quantity.get("plan:"+transferOrderLine.getBizNo()+transferOrderLine.getLineNo()+":in"));
			transferOrderLine.setPlanOutQuantity(quantity.get("plan:"+transferOrderLine.getBizNo()+transferOrderLine.getLineNo()+":out"));
			transferOrderLine.setPlanRejctInQuantity(quantity.get("planReject:"+transferOrderLine.getBizNo()+transferOrderLine.getLineNo()+":in"));
			transferOrderLine.setPlanRejctOutQuantity(quantity.get("planReject:"+transferOrderLine.getBizNo()+transferOrderLine.getLineNo()+":out"));
		});
	}

}
